﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace EETOP.OAuthSDK
{
    /// <summary>
    /// An OAuthService encapsulates protocol information about a set of OAuth endpoints.
    /// </summary>
    /// 
    /// <remarks>
    /// <para>An OAuthService contains the following protocol information:</para>
    /// 
    /// <list type="bullet">
    /// <item><description>The URL for obtaining Request Tokens</description></item>
    /// <item><description>The URL to send users to for authorization</description></item>
    /// <item><description>The URL for obtaining Access Tokens</description></item>
    /// <item><description>The HTTP method to use (GET or POST)</description></item>
    /// <item><description>Whether Authorization HTTP headers should be used</description></item>
    /// <item><description>The authorization Realm</description></item>
    /// <item><description>The signature method to use</description></item>
    /// <item><description>The OAuth specification version</description></item>
    /// <item><description>The consumer details (key and secret)</description></item>
    /// </list>
    /// 
    /// <para>In future, it should be possible to perform automatic discovery of
    /// the protocol information (a discovery specification is being worked on), but
    /// for now this information must be supplied.</para>
    /// </remarks>
    [DebuggerDisplay("Request Token URL: {RequestTokenUrl} Authorization URL: {AuthorizationUrl} Access Token URL: {AccessTokenUrl} Http Method: {HttpMethod}  Signature Method: {SignatureMethod} OAuth Version: {OAuthVersion} Consumer: {Consumer}")]
    public class OAuthSettings
    {
        // Uninstantiable except via factory methods
        private OAuthSettings()
        {
        }


        /// <summary>
        /// The URL to Call back
        /// </summary>
        public Uri CallBackUrl
        {
            get;
            private set;
        }
        /// <summary>
        /// The EndPoint for obtaining request tokens
        /// </summary>
        public EndPoint RequestTokenEndPoint
        {
            get;
            private set;
        }

        /// <summary>
        /// The URL for obtaining request tokens
        /// </summary>
        public Uri RequestTokenUrl
        {
            get
            {
                return this.RequestTokenEndPoint.Uri;
            }
        }

        /// <summary>
        /// The URL to send users to for authorization
        /// </summary>
        public Uri AuthorizationUrl
        {
            get;
            private set;
        }

        /// <summary>
        /// The EndPoint for obtaining access tokens
        /// </summary>
        public EndPoint AccessTokenEndPoint
        {
            get;
            private set;
        }

        /// <summary>
        /// The URL for obtaining access tokens
        /// </summary>
        public Uri AccessTokenUrl
        {
            get
            {
                return this.AccessTokenEndPoint.Uri;
            }
        }

        /// <summary>
        /// Whether to use HTTP Authorization headers (or query string / post body instead)
        /// </summary>
        public bool UseAuthorizationHeader
        {
            get;
            private set;
        }



        /// <summary>
        /// The signature method to use
        /// </summary>
        public string SignatureMethod
        {
            get;
            private set;
        }

        /// <summary>
        /// The OAuth specification version
        /// </summary>
        /// <value>Must be <c>1.0</c></value>
        public string OAuthVersion
        {
            get;
            private set;
        }

        /// <summary>
        /// The consumer credentials
        /// </summary>
        public IConsumer Consumer
        {
            get;
            private set;
        }

        public static OAuthSettings Create(EndPoint requestTokenEndPoint, Uri authorizationurl, EndPoint accessTokenEndPoint, Uri callbackurl, IConsumer consumer)
        {
            OAuthSettings sets = new OAuthSettings();
            sets.RequestTokenEndPoint = requestTokenEndPoint;
            sets.AccessTokenEndPoint = accessTokenEndPoint;
            sets.AuthorizationUrl = authorizationurl;
            sets.CallBackUrl = callbackurl;
            sets.Consumer = consumer;
            return sets;
        }

        /// <summary>
        /// Checks if two OAuthServices are equal
        /// </summary>
        /// <param name="left">Left-hand-side OAuthService</param>
        /// <param name="right">Right-hand-side OAuthService</param>
        /// <returns><c>true</c>, if they are equal; otherwise <c>false</c></returns>
        public static bool operator ==(OAuthSettings left, OAuthSettings right)
        {
            if (object.ReferenceEquals(left, right))
                return true;

            if (((object)left) == null && ((object)right) == null)
                return true;

            return left.Equals(right);
        }

        /// <summary>
        /// Checks if two OAuthServices are not equal
        /// </summary>
        /// <param name="left">Left-hand-side OAuthService</param>
        /// <param name="right">Right-hand-side OAuthService</param>
        /// <returns><c>true</c>, if they are not equal; otherwise <c>false</c></returns>
        public static bool operator !=(OAuthSettings left, OAuthSettings right)
        {
            return !(left == right);
        }


        /// <summary>
        /// Gets a hash code for the OAuthService.
        /// </summary>
        /// <returns>A hash code, computed from the hash codes of the properties</returns>
        public override int GetHashCode()
        {
            return this.RequestTokenEndPoint.GetHashCode()
                ^ this.AuthorizationUrl.GetHashCode() ^ this.AccessTokenEndPoint.GetHashCode()
                ^ this.SignatureMethod.GetHashCode()
                ^ this.OAuthVersion.GetHashCode() ^ this.Consumer.GetHashCode();
        }

        /// <summary>
        /// Checks whether the supplied object is equal to this OAuthService object.
        /// </summary>
        /// <remarks>OAuthServices are compared property by property.</remarks>
        /// <param name="obj">Object</param>
        /// <returns><c>true</c> if the objects' properties have the same values;
        /// <c>false</c> otherwise</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (System.Object.ReferenceEquals(this, obj))
                return true;

            if (this.GetType() != obj.GetType())
                return false;

            return this.Equals(obj as OAuthSettings);
        }

        /// <summary>
        /// Checks whether the supplied OAuthService is equal to this OAuthService object.
        /// </summary>
        /// <remarks>OAuthServices are compared property by property (excluding 
        /// ComponentLocator).</remarks>
        /// <param name="other">Other OAuthService</param>
        /// <returns><c>true</c> if the OAuthServices' properties have the same values;
        /// <c>false</c> otherwise</returns>
        private bool Equals(OAuthSettings other)
        {
            return other != null
                && this.RequestTokenEndPoint.Equals(other.RequestTokenUrl)
                && this.AuthorizationUrl.Equals(other.AuthorizationUrl)
                && this.AccessTokenEndPoint.Equals(other.AccessTokenUrl)
                && this.UseAuthorizationHeader == other.UseAuthorizationHeader
                && string.Equals(this.SignatureMethod, other.SignatureMethod)
                && string.Equals(this.OAuthVersion, other.OAuthVersion)
                && this.Consumer.Equals(other.Consumer);
        }
    }
}